<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script id="ColorVS" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform float u_PointSize;
    uniform mat4 u_ModelM4;
    uniform mat4 u_PvM4;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = u_PointSize;
    }
</script>
<script id="ColorFS" type="x-shader/x-fragment">
    precision mediump float;
    uniform vec4 u_Color;
    void main(){
        gl_FragColor = u_Color;
    }
</script>
<script id="ImageVS" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    attribute vec2 a_Pin;
    uniform mat4 u_ModelM4;
    uniform mat4 u_PvM4;
    varying vec2 v_Pin;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = 30.0;
        v_Pin = a_Pin;
    }
</script>
<script id="ImageFS" type="x-shader/x-fragment">
    precision mediump float;
    uniform sampler2D u_Sampler;
    varying vec2 v_Pin;
    void main(){
        gl_FragColor = texture2D(u_Sampler, v_Pin);
    }
</script>
<script id="ZoomVS" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    attribute vec3 a_Normal;
    uniform mat4 u_ModelM4;
    uniform mat4 u_PvM4;
    varying vec4 v_Posi;
    varying vec3 v_Normal;
    varying vec2 v_Center;
    void main(){
        vec4 posi = u_PvM4 * u_ModelM4 * a_Position;
        gl_Position = posi;
        v_Posi = posi;
        v_Normal = normalize(a_Normal);
        v_Center = (u_ModelM4 * vec4(vec3(0), 1.0)).xy; 
    }
</script>
<script id="ZoomFS" type="x-shader/x-fragment">
    precision mediump float;
    uniform sampler2D u_Sampler;
    uniform vec3 u_EyeDir;
    varying vec2 v_Center;
    varying vec4 v_Posi;
    varying vec3 v_Normal;
    void main(){
        vec3 fragPos = (v_Posi.xyz / v_Posi.w) / 2.0 + 0.5;
        vec2 c = v_Center.xy / 2.0 + 0.5;

        float b = 0.2;
        fragPos.x = (fragPos.x - c.x) * b + fragPos.x;
        fragPos.y = (c.y - fragPos.y) * b + fragPos.y;
        vec4 color = texture2D(u_Sampler, fragPos.xy);

        float _RimAmount = 0.1;
        float NdotV = 1.0 - dot(v_Normal, u_EyeDir);
        float rimSmooth = max(0.0, NdotV) * smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, NdotV);
        vec3 lr = rimSmooth * vec3(0.0, 0.5, 1.0);
        vec3 color1 = lr + vec3(color).rgb;

        gl_FragColor = vec4(color1, color.a);
    }
</script>
<script id="ViewVS" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    attribute vec2 a_Pin;
    uniform mat4 u_ModelM4;
    uniform mat4 u_PvM4;
    varying vec2 v_Pin;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
        gl_PointSize = 30.0;
        v_Pin = a_Pin;
    }
</script>
<script id="ViewFS" type="x-shader/x-fragment">
    precision mediump float;
    uniform sampler2D u_Sampler;
    varying vec2 v_Pin;
    void main(){
       gl_FragColor = texture2D(u_Sampler, v_Pin);
    }
</script>
<script type="module">
    import { Matrix4, Vector3, Color, OrthographicCamera, PerspectiveCamera, Spherical } from '../js/three.module.js';
    import { CreateProgram, imgPromise } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';
    import CameraController from '../js/CameraController.js'
    import Poly from '../js/Poly4.js'
    import Control from '../js/Control.js'
    import Earth from '../js/objs/Earth.js'
    import Square from '../js/objs/Square.js'

    import Geo from '../js/Poly2/Geo.js'
    import Mat from '../js/Poly2/Mat.js'
    import Obj3D from '../js/Poly2/Obj3D.js'
    import Scene from '../js/Poly2/Scene.js'
    import Frame from '../js/Poly2/Frame.js'



    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    const gl = canvas.getContext("webgl", { antialias: true, });

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);//去图片描边
    gl.enable(gl.DEPTH_TEST);
    //#endregion

    const frame = new Frame({ gl: gl });
    const scene = new Scene({ gl: gl });
    frame.addAxisProgram();
    frame.regProgram('color', {
        program: CreateProgram(gl, document.querySelector('#ColorVS').innerText, document.querySelector('#ColorFS').innerText),
        attribs: ['a_Position'],
        uniforms: ['u_PvM4', 'u_ModelM4', 'u_PointSize', 'u_Color']
    });
    frame.regProgram('image', {
        program: CreateProgram(gl, document.querySelector('#ImageVS').innerText, document.querySelector('#ImageFS').innerText),
        attribs: ['a_Position', 'a_Pin'],
        uniforms: ['u_PvM4', 'u_ModelM4', 'u_Sampler']
    });
    frame.regProgram('zoom', {
        program: CreateProgram(gl, document.querySelector('#ZoomVS').innerText, document.querySelector('#ZoomFS').innerText),
        attribs: ['a_Position', 'a_Normal'],
        uniforms: ['u_PvM4', 'u_ModelM4', 'u_Sampler', 'u_EyeDir', 'u_Center']
    });
    scene.regProgram('view', {
        program: CreateProgram(gl, document.querySelector('#ViewVS').innerText, document.querySelector('#ViewFS').innerText),
        attribs: ['a_Position', 'a_Pin'],
        uniforms: ['u_PvM4', 'u_ModelM4', 'u_Sampler']
    });
    scene.regProgram('color', {
        program: CreateProgram(gl, document.querySelector('#ColorVS').innerText, document.querySelector('#ColorFS').innerText),
        attribs: ['a_Position'],
        uniforms: ['u_PvM4', 'u_ModelM4', 'u_PointSize', 'u_Color']
    });


    const pvM4 = new Matrix4();
    const modelM4 = new Matrix4();
    const eye = new Vector3(0, 0, 2);
    const lookAt = new Vector3();

    const camera = new PerspectiveCamera(45, canvas.width / canvas.height, 1, 20);
    const cameraController = new CameraController({
        canvas,
        camera,
        pvMatrix: pvM4,
        eye,
        lookAt,
    });



    // const axis = new Obj3D().createAxis('axis');
    // frame.add(axis);

    const [faceW, faceH] = [0.6, 0.5];
    const [faceVertices, faceElements] = [
        [
            -faceW, faceH, 0,
            -faceW, -faceH, 0,
            faceW, -faceH, 0,
            faceW, faceH, 0,
        ], [0, 1, 2, 0, 2, 3]
    ];



    //#region main
    //屏幕对象

    const view = createView();
    scene.add(view);


    const earth = new Earth();
    const geo = new Geo({
        data: {
            'a_Position': { size: 3, array: new Float32Array(earth.vertices) },
            'a_Normal': { size: 3, array: new Float32Array(earth.normals) },
        },
        element: { array: new Uint16Array(earth.elements) }
    });
    const mat = new Mat({
        program: 'zoom',
        mode: ['TRIANGLES'],
        data: {
            'u_PvM4': { type: 'uniformMatrix4fv', value: pvM4.elements },
            'u_ModelM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
            'u_EyeDir': { type: 'uniform3fv', value: [...eye.clone().sub(lookAt)] },
        },
    });
    const sphere3D = new Obj3D({ geo: geo, mat: mat, });
    frame.addLast(sphere3D);



    const image = new Image();
    image.src = '../Image/Image01.jpg';
    image.onload = function () {

        //创建
        frame.add(createImage(faceVertices, faceElements, image, new Matrix4().setPosition(0, 0, -0.5)));


        // const square = new Square(0.5);
        // const [squareVertices, squareElements, squareNormals] = [
        //     square.vertices, square.elements, square.normals
        // ];
        // let obj01 = create(squareVertices, squareElements, [1, 1, 1, 1])
        // scene.add(obj01);

    };

    canvas.addEventListener('mousemove', function (e) {
        const { clientX, clientY } = e;
        const cur = getViewToWorld(clientX, clientY);

        sphere3D.setUniform('u_ModelM4', { value: new Matrix4().setPosition(cur.x, cur.y, 0).elements });
    })
    function getViewToWorld(clientX, clientY) {
        const [hx, hy] = [canvas.width / 2, canvas.height / 2];
        const [x, y] = [(clientX - hx) / hx, -(clientY - hy) / hy];
        const worldPosi = new Vector3(x, y, 0).applyMatrix4(pvM4.clone().invert())
        return worldPosi;
    }

    //#endregion



    (function ani(time) {
        draw();
        requestAnimationFrame(ani)
    })(0);

    function createView() {
        const w = 1;
        const h = 1;
        const geo = new Geo({
            data: {
                'a_Position': {
                    size: 3, array: new Float32Array([
                        -w, h, 0,
                        -w, -h, 0,
                        w, -h, 0,
                        w, h, 0,
                    ])
                },
                'a_Pin': { size: 2, array: new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]) },
            },
            element: { array: new Uint16Array([0, 1, 2, 0, 2, 3]) }
        });
        const mat = new Mat({
            program: 'view',
            mode: ['TRIANGLES'],
            data: {
                'u_PvM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
                'u_ModelM4': { type: 'uniformMatrix4fv', value: new Matrix4().elements },
            },
        });
        return new Obj3D({ geo: geo, mat: mat, });
    }
    function createImage(vertices, elements, image, mm4 = new Matrix4()) {
        const geo = new Geo({
            data: {
                'a_Position': { size: 3, array: new Float32Array(vertices) },
                'a_Pin': { size: 2, array: new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]) },
            },
            element: { array: new Uint16Array(elements) }
        });
        const mat = new Mat({
            program: 'image',
            mode: ['TRIANGLES'],
            data: {
                'u_PvM4': { type: 'uniformMatrix4fv', value: pvM4.elements },
                'u_ModelM4': { type: 'uniformMatrix4fv', value: mm4.elements },
            },
            maps: {
                'u_Sampler': {
                    image: image,
                    WRAP_W: gl.CLAMP_TO_EDGE,
                    WRAP_H: gl.CLAMP_TO_EDGE,
                    MIN_FILTER: gl.LINEAR,
                },
            }
        });
        return new Obj3D({ geo: geo, mat: mat, });
    }
    function create(vertices, elements = null, color = [Math.random(), Math.random(), Math.random(), 1]) {
        const geo = new Geo({
            data: {
                'a_Position': { size: 3, array: new Float32Array(vertices) },
            }
        });
        const mat = new Mat({
            program: 'color',
            mode: ['LINES', 'POINTS'],
            data: {
                'u_PvM4': { type: 'uniformMatrix4fv', value: pvM4.elements },
                'u_ModelM4': { type: 'uniformMatrix4fv', value: modelM4.elements },
                'u_PointSize': { type: 'uniform1f', value: 30 },
                'u_Color': { type: 'uniform4fv', value: color },
            },
        });
        if (elements != null) {
            geo.element = { array: new Uint16Array(elements) };
            mat.mode = ['TRIANGLES'];
        }
        return new Obj3D({ geo: geo, mat: mat, });
    }


    function draw() {
        frame.setUniform('u_PvM4', { value: pvM4.elements });
        frame.setLastUniform('u_EyeDir', { value: [...eye.clone().sub(lookAt)] });

        const texure = frame.draw();
        sphere3D.addTexure(gl, 'u_Sampler', { texture: texure });

        const texure1 = frame.drawLast();
        view.addTexure(gl, 'u_Sampler', { texture: texure1 });

        scene.draw();

    }
</script>

</html>